﻿/*
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * See product pages for more information.
 * http://closesudoku.codeplex.com
 * Copyright (C), 2010, hrondra
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Microsoft.Win32;

namespace Close.Classes
{
    class PowerSaving
    {
        [System.Runtime.InteropServices.DllImport("CoreDll.dll")]
        public static extern void SystemIdleTimerReset();

        private static System.Threading.Timer preventSleepTimer = null;

        /// <summary>
        /// Return the shorter (without)battery interval
        /// </summary>
        /// <returns>milliseconds</returns>
        /// <remarks>//see http://www.codeproject.com/KB/windows/WiMoPower1.aspx?msg=2874672</remarks>
        private static int ShortestTimeoutInterval()
        {
            int retVal = 1000;
            RegistryKey key = Registry.LocalMachine.OpenSubKey(
                        @"\SYSTEM\CurrentControlSet\Control\Power");
            object oBatteryTimeout = key.GetValue("BattPowerOff");
            object oACTimeOut = key.GetValue("ExtPowerOff");
            object oScreenPowerOff = key.GetValue("ScreenPowerOff");

            if (oBatteryTimeout is int)
            {
                int v = (int)oBatteryTimeout;
                if (v > 0)
                    retVal = Math.Min(retVal, v);
            }
            if (oACTimeOut is int)
            {
                int v = (int)oACTimeOut;
                if (v > 0)
                    retVal = Math.Min(retVal, v);
            }
            if (oScreenPowerOff is int)
            {
                int v = (int)oScreenPowerOff;
                if (v > 0)
                    retVal = Math.Min(retVal, v);
            }

            //Since the interval is in seconds and out timer
            //operates in milliseconds the value needs to be multiplied
            //by 1000 to get the appropriate millisecond value. I've
            //multiplied by 900 instead so that I ensure that I call
            //SystemIdleTimerReset before the timeout is reached.
            return retVal * 900;
        }

        //TODO: setable interval

        /// <summary>
        /// Disable power saving mode for display.
        /// </summary>
        public static void DisableDeviceSleep()
        {
            int shortestIdle = ShortestTimeoutInterval();

            // start a 30-second periodic timer
            preventSleepTimer = new System.Threading.Timer(new TimerCallback(PokeDeviceToKeepAwake),
                null, 0, shortestIdle - 1);

        }
        /// <summary>
        /// Enable power saving mode for display.
        /// </summary>
        public static void EnableDeviceSleep()
        {
            if (preventSleepTimer != null)
            {
                preventSleepTimer.Dispose();
                preventSleepTimer = null;
            }
        }

        /// <summary>
        /// Refresh display (reset timer).
        /// </summary>
        private static void PokeDeviceToKeepAwake(object extra)
        {
            try
            {
                SystemIdleTimerReset();
            }
            catch (Exception e)
            {
                MyLog.Write(MyLog.LogType.Error, "PowerSaving", string.Empty, e);
            }
        }
    }
}
